package baseFx.common.caching.mysql;

import baseFx.common.caching.Cache;
import baseFx.common.caching.CacheItem;
import baseFx.common.utils.ClassUtils;
import baseFx.database.execute.DbExecute;
import baseFx.serialization.json.JsonUtils;

public class MysqlCache implements Cache {
    private DbExecute execute;

    public MysqlCache(DbExecute execute) {
        this.execute = execute;
    }

    protected String serialize(Object value) {
        return JsonUtils.toJson(value);
    }

    protected Object deserialize(String json, Class<?> clazz) {
        if (json.startsWith("[")) {
            return JsonUtils.toList(json, clazz);
        }
        return JsonUtils.toObject(json, clazz);
    }

    @Override
    public void save(CacheItem item) {
        if (item.value == null) {
            throw new NullPointerException("item.value");
        }
        MysqlCacheItem mysqlitem = MysqlCacheItem.convert(item, serialize(item.value), item.value.getClass().getCanonicalName());
        MysqlCacheItem qo = new MysqlCacheItem();
        qo.key = mysqlitem.key;
        MysqlCacheItem old = execute.query().get(MysqlCacheItem.class, qo);
        if (old == null) {
            execute.insert(mysqlitem);
        } else {
            mysqlitem.key = null;
            execute.update(mysqlitem, qo);
        }
    }

    @Override
    public void remove(String key) {
        execute.deleteby(MysqlCacheItem.class, i -> i.key = key);
    }

    @Override
    public void update(String key, Object value) {
        MysqlCacheItem wo = new MysqlCacheItem();
        wo.key = key;
        MysqlCacheItem item = execute.query().get(MysqlCacheItem.class, wo);
        if (item != null) {
            item = new MysqlCacheItem();
            item.clazz = value.getClass().getCanonicalName();
            item.getTime = System.currentTimeMillis();
            item.value = serialize(value);
            execute.update(item, wo);
        }
    }

    @Override
    public boolean exists(String key) {
        return execute.query().countby(MysqlCacheItem.class, i -> i.key = key) > 0;
    }

    @Override
    public Object get(String key) {
        MysqlCacheItem wo = new MysqlCacheItem();
        wo.key = key;
        MysqlCacheItem item = execute.query().get(MysqlCacheItem.class, wo);
        if (item == null) {
            return null;
        }
        if (item.slidingExpiration != null) {
            long mills = item.getTime + item.slidingExpiration * 1000;
            if (mills < System.currentTimeMillis()) {
                return null;
            }
        }
        if (item.absoluteExpiration != null) {
            long mills = item.getTime + item.absoluteExpiration * 1000;
            if (mills < System.currentTimeMillis()) {
                return null;
            }
        }
        return deserialize(item.value, ClassUtils.getClassForName(item.clazz));
    }
}
